use sorted_array::sorted_array::{SortedArray, SortedArrayEqualFunc, SortedArrayCompareFunc};
use std::cmp::Ordering;

const TEST_SIZE: usize = 20;
const TEST_ARRAY: [i32; TEST_SIZE] = [10, 12, 12, 1, 2, 3, 6, 7, 2, 23, 13, 23, 23, 34, 31, 9, 21, -2, -12, -4];
const TEST_REMOVE_EL: usize = 15;
const TEST_REMOVE_RANGE: usize = 7;
const TEST_REMOVE_RANGE_LENGTH: usize = 4;

fn int_equal(a: &i32, b: &i32) -> bool {
    *a == *b
}

fn int_compare(a: &i32, b: &i32) -> Ordering {
    a.cmp(b)
}

fn generate_sortedarray_equ(equ_func: SortedArrayEqualFunc<i32>) -> SortedArray<i32> {
    let mut sortedarray = SortedArray::new(0, equ_func, int_compare);
    for &item in &TEST_ARRAY {
        sortedarray.insert(item);
    }
    sortedarray
}

fn generate_sortedarray() -> SortedArray<i32> {
    generate_sortedarray_equ(int_equal)
}

fn check_sorted_prop(sortedarray: &SortedArray<i32>) {
    for i in 1..sortedarray.len() {
        assert!(int_compare(sortedarray.get(i - 1).unwrap(), sortedarray.get(i).unwrap()) <= Ordering::Equal);
    }
}

#[test]
fn test_sortedarray_new_free() {
    let sortedarray = SortedArray::new(0, int_equal, int_compare);
    assert!(sortedarray.len() == 0);

    // Test freeing null is not applicable in Rust
}

#[test]
fn test_sortedarray_insert() {
    let mut sortedarray = generate_sortedarray();
    for _ in 0..20 {
        let i = rand::random::<i32>() % 100;
        sortedarray.insert(i);
    }
    check_sorted_prop(&sortedarray);
}

#[test]
fn test_sortedarray_remove() {
    let mut sortedarray = generate_sortedarray();
    let ip = *sortedarray.get(TEST_REMOVE_EL + 1).unwrap();
    sortedarray.remove(TEST_REMOVE_EL);
    assert_eq!(*sortedarray.get(TEST_REMOVE_EL).unwrap(), ip);
    check_sorted_prop(&sortedarray);
}

#[test]
fn test_sortedarray_remove_range() {
    let mut sortedarray = generate_sortedarray();
    let new: Vec<i32> = (0..TEST_REMOVE_RANGE_LENGTH)
        .map(|i| *sortedarray.get(TEST_REMOVE_RANGE + TEST_REMOVE_RANGE_LENGTH + i).unwrap())
        .collect();
    sortedarray.remove_range(TEST_REMOVE_RANGE, TEST_REMOVE_RANGE_LENGTH);
    for i in 0..TEST_REMOVE_RANGE_LENGTH {
        assert_eq!(*sortedarray.get(TEST_REMOVE_RANGE + i).unwrap(), new[i]);
    }
    check_sorted_prop(&sortedarray);
}

#[test]
fn test_sortedarray_index_of() {
    let sortedarray = generate_sortedarray();
    for i in 0..TEST_SIZE {
        let r = sortedarray.index_of(sortedarray.get(i).unwrap()).unwrap();
        assert!(r >= 0);
        assert_eq!(*sortedarray.get(r).unwrap(), *sortedarray.get(i).unwrap());
    }
}

fn ptr_equal(a: &i32, b: &i32) -> bool {
    a as *const i32 == b as *const i32
}

#[test]
fn test_sortedarray_index_of_equ_key() {
    let sortedarray = generate_sortedarray_equ(ptr_equal);
    for i in 0..TEST_SIZE {
        let r = sortedarray.index_of(sortedarray.get(i).unwrap()).unwrap();
        assert_eq!(i, r);
    }
}

#[test]
fn test_sortedarray_get() {
    let arr = generate_sortedarray();
    for i in 0..arr.len() {
        assert_eq!(arr.get(i), arr.get(i));
        assert_eq!(*arr.get(i).unwrap(), *arr.get(i).unwrap());
    }
}